#include "moverbutton.h"
#include <stdexcept>
#include <QPainter>
#include <QMatrix>

using namespace ExecTerminalImplNS;


const int STATES_COUNT = 3;
const int BACKGROUND_PIXMAPS_OFFSET = 0;
const int ARROW_PIXMAPS_OFFSET = STATES_COUNT;
const int PIX_TYPE_COUNT = 2;

const int NORMAL_OFFSET = 0;
const int HOVER_OFFSET = 1;
const int PRESSED_OFFSET = 2;

MoverButton::MoverButton(QWidget * parent): QPushButton(parent),
theOrientation(UP_ORIENTATION)
{
    if (parent == 0)
    {
        throw std::invalid_argument("MoverButton::MoverButton(): parent must not be null");
    }
    for (int i = 0; i < PIX_TYPE_COUNT * STATES_COUNT; ++i)
    {
        theButtonPixmaps << QPixmap();
    }
    connect(this, SIGNAL(clicked()), SLOT(changeOrientation()));
}


void MoverButton::setArrowPixmaps(const QPixmap & normal, 
                     const QPixmap & hover, 
                     const QPixmap & pressed)
{
    theButtonPixmaps[ARROW_PIXMAPS_OFFSET + NORMAL_OFFSET] = normal;
    theButtonPixmaps[ARROW_PIXMAPS_OFFSET + HOVER_OFFSET] = hover;
    theButtonPixmaps[ARROW_PIXMAPS_OFFSET + PRESSED_OFFSET] = pressed;
    update();
}

void MoverButton::setBackgroundPixmaps(const QPixmap & normal, 
                          const QPixmap & hover, 
                          const QPixmap & pressed)
{
    theButtonPixmaps[BACKGROUND_PIXMAPS_OFFSET + NORMAL_OFFSET] = normal;
    theButtonPixmaps[BACKGROUND_PIXMAPS_OFFSET + HOVER_OFFSET] = hover;
    theButtonPixmaps[BACKGROUND_PIXMAPS_OFFSET + PRESSED_OFFSET] = pressed;
    update();
}

void MoverButton::enterEvent(QEvent * )
{
    update();
}

void MoverButton::leaveEvent(QEvent * )
{
    update();
}

void MoverButton::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    QMatrix rotateMatr;
    switch(theOrientation)
    {
    case LEFT_ORIENTATION:
    case RIGHT_ORIENTATION:
        rotateMatr.translate(0, height());
        rotateMatr.rotate(90 + 180);
        painter.setMatrix(rotateMatr);
        break;
    default:
        break;
    }
    painter.drawPixmap(0, 0, backgrnPix());

    const QPixmap & arrow = arrowPix();
    const bool horOrnt = isHorOrientation(theOrientation);
    const int leftMargin = (horOrnt ? height() : width()) / 2 - arrow.width() / 2;
    rotateMatr.translate(leftMargin, topMarginForArrow());
    switch(theOrientation)
    {
    case DOWN_ORIENTATION:
    case RIGHT_ORIENTATION:
        {
            rotateMatr.translate(arrow.width(), arrow.height());
            rotateMatr.rotate(180);
        }
    	break;
    default:
        break;
    }
    painter.setMatrix(rotateMatr);
    painter.drawPixmap(0, 0, arrowPix());
}

const QPixmap & MoverButton::backgrnPix()const
{
    return pixForState(BACKGROUND_PIXMAPS_OFFSET);
}

const QPixmap & MoverButton::arrowPix()const
{
    return pixForState(ARROW_PIXMAPS_OFFSET);
}

const QPixmap & MoverButton::pixForState(int offset)const
{
    if (isDown())
    {
        return theButtonPixmaps.at(offset + PRESSED_OFFSET);
    }
    if (underMouse())
    {
        return theButtonPixmaps.at(offset + HOVER_OFFSET);
    }
    return theButtonPixmaps.at(offset + NORMAL_OFFSET);
}

void MoverButton::changeOrientation()
{
    switch(theOrientation)
    {
    case UP_ORIENTATION:
        setOrientation(DOWN_ORIENTATION);
    	break;
    case DOWN_ORIENTATION:
        setOrientation(UP_ORIENTATION);
    	break;
    case LEFT_ORIENTATION:
        setOrientation(RIGHT_ORIENTATION);
        break;
    case RIGHT_ORIENTATION:
        setOrientation(LEFT_ORIENTATION);
        break;
    default:
        break;
    }
}
    
void MoverButton::setOrientation(Orientation ornt)
{
    if (isHorOrientation(ornt) != isHorOrientation(theOrientation))
    {
//        resize(height(), width());
    }
    if (ornt != theOrientation)
    {
        theOrientation = ornt;
        update();
    }
}

void MoverButton::switchOrientationToPerpendicular()
{
    switch(theOrientation)
    {
    case UP_ORIENTATION:
        setOrientation(LEFT_ORIENTATION);
        break;
    case DOWN_ORIENTATION:
        setOrientation(RIGHT_ORIENTATION);
        break;
    case LEFT_ORIENTATION:
        setOrientation(UP_ORIENTATION);
        break;
    case RIGHT_ORIENTATION:
        setOrientation(DOWN_ORIENTATION);
        break;
    default:
        break;
    }
}
